package com.euc.springbootframework.util;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class DateUtils {
    public static String DATE_TYPE_DAY = "day";
    public static String DATE_TYPE_HOURS = "hour";
    public static String DATE_TYPE_MIN = "minute";
    public static String DATE_TYPE_SEC = "second";
    public static DateTimeFormatter YEAR_MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");
    public static DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    private static final List<DateTimeFormatter> formarts = new ArrayList<DateTimeFormatter>(4);
    static{
        formarts.add(DateTimeFormatter.ofPattern("yyyy-MM"));
        formarts.add(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        formarts.add(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        formarts.add(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static LocalDateTime toLocalDateTime(String dateString){
        if(dateString.matches("^\\d{4}-\\d{1,2}$")){
            return LocalDateTime.parse(dateString, formarts.get(0));
        }else if(dateString.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")){
            return LocalDateTime.parse(dateString, formarts.get(1));
        }else if(dateString.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")){
            return LocalDateTime.parse(dateString, formarts.get(2));
        }else if(dateString.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")){
            return LocalDateTime.parse(dateString, formarts.get(3));
        }else {
            throw new IllegalArgumentException("Invalid Date value '" + dateString + "'");
        }
    }

    public static Date getDateBefore(Date d, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(d);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - day);
        return now.getTime();
    }

    public static Date getDateAfter(Date d, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(d);
        now.set(Calendar.DATE, now.get(Calendar.DATE) + day);
        return now.getTime();
    }

    public static double daysOfTwo(Date fDate, Date oDate, String type) {
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.setTime(fDate);
        calendar2.setTime(oDate);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;

        if (type == null || type.equals("")) {
            type = DATE_TYPE_DAY;
        }

        if (type.equals(DATE_TYPE_SEC)) {
            return new BigDecimal(diff / 1000).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        } else if (type.equals(DATE_TYPE_MIN)) {
            return new BigDecimal(diff / (60 * 1000)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        } else if (type.equals(DATE_TYPE_HOURS)) {
            return new BigDecimal(diff / (60 * 60 * 1000)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        } else if (type.equals(DATE_TYPE_DAY)) {
            return new BigDecimal(diff / (24 * 60 * 60 * 1000)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        } else {
            return 0;
        }
    }

    public static String formatDate(String formatString, Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatString, Locale.US);
        return sdf.format(date);
    }

    public static int getYear(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }

    public static int getMonth(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH)+1;
    }

    public static String getNextMonth(String month){
        return LocalDate.parse(month,YEAR_MONTH_FORMATTER).plusMonths(1).format(YEAR_MONTH_FORMATTER);
    }

    public static int getDaysOfYear(int year) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        return cal.getActualMaximum(Calendar.DAY_OF_YEAR);
    }

    public static int getDaysOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DAY_OF_YEAR);
    }

    public static int getDaysOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    public static int getDaysOfMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month);
        return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    public static Date getFirstDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    public static Date getLastDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        cal.set(Calendar.DAY_OF_MONTH, max);
        return cal.getTime();
    }

    public static Date getFirstDayOfMonth(int year,int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR,year);
        cal.set(Calendar.MONTH, month-1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    public static Date getLastDayOfMonth(int year,int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR,year);
        cal.set(Calendar.MONTH, month-1);
        int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        cal.set(Calendar.DAY_OF_MONTH, max);
        return cal.getTime();
    }

    public static int getMonthsBetween(Date start, Date end) {
        if (start.after(end)) {
            Date t = start;
            start = end;
            end = t;
        }

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(start);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(end);
        Calendar temp = Calendar.getInstance();
        temp.setTime(end);
        temp.add(Calendar.DATE, 1);

        int year = endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR);
        int month = endCalendar.get(Calendar.MONTH) - startCalendar.get(Calendar.MONTH);

        if ((startCalendar.get(Calendar.DATE) == 1) && (temp.get(Calendar.DATE) == 1)) {
            return year * 12 + month + 1;
        } else if ((startCalendar.get(Calendar.DATE) != 1) && (temp.get(Calendar.DATE) == 1)) {
            return year * 12 + month;
        } else if ((startCalendar.get(Calendar.DATE) == 1) && (temp.get(Calendar.DATE) != 1)) {
            return year * 12 + month;
        } else {
            return (year * 12 + month - 1) < 0 ? 0 : (year * 12 + month);
        }
    }

    public static final int getDaysBetween(Date startDate, Date endDate) {
        Calendar calst = Calendar.getInstance();
        Calendar caled = Calendar.getInstance();
        calst.setTime(startDate);
        caled.setTime(endDate);

        calst.set(java.util.Calendar.HOUR_OF_DAY, 0);
        calst.set(java.util.Calendar.MINUTE, 0);
        calst.set(java.util.Calendar.SECOND, 0);
        caled.set(java.util.Calendar.HOUR_OF_DAY, 0);
        caled.set(java.util.Calendar.MINUTE, 0);
        caled.set(java.util.Calendar.SECOND, 0);
        int days = ((int) (caled.getTime().getTime() / 1000) -
                (int) (calst.getTime().getTime() / 1000)) / 3600 / 24;

        return days;
    }

    public static Date getSpecifiedDayOfSpecifiedMonth(Integer day, Integer addMonth, Integer specifiedMonth){
        Calendar c = Calendar.getInstance();
        if(specifiedMonth != null){
            c.set(Calendar.MONTH, specifiedMonth);
        }else{
            c.add(Calendar.MONTH, addMonth);
        }
        c.set(Calendar.DAY_OF_MONTH, day);
        c.set(Calendar.HOUR_OF_DAY, 8);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
//		 System.out.println(c.getTime());
        return c.getTime();
    }

    public static Date getYearMonthDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }
}
